#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "QTimer"
#include "QPalette"
#include "QSystemTrayIcon"
#include "QDateTime"
#include "QMenu"
#include "rxqt/include/rxqt.hpp"
#include <windows.h>
#include <QSound>


using namespace std::chrono;

namespace Rx {
    using namespace rxcpp;
    using namespace rxcpp::sources;
    using namespace rxcpp::operators;
    using namespace rxcpp::util;
}

template<class T> class Data
{
public:
    Data() : _subscriber(_subject.get_subscriber()) { }
    ~Data()  { _subscriber.on_completed(); }
    void publish(T data) { _subscriber.on_next(data); }
    rxcpp::observable<T> observable() { return _subject.get_observable(); }

private:
    rxcpp::subjects::subject<T> _subject;
    rxcpp::subscriber<T> _subscriber;
};

Data<int> gData;         // 用作监控鼠标的移动 subject
Data<int> gRestData;     // 用作监控自动结束休息
Data<int> gClickContinue;

HHOOK mouseHook = nullptr;
int gCounter = 0;
LRESULT CALLBACK mouseProc(int nCode, WPARAM wParam, LPARAM lParam )
{
    if(nCode == HC_ACTION) //当nCode等于HC_ACTION时，要求得到处理
    {
       if(wParam==WM_MOUSEMOVE || wParam==WM_KEYDOWN)
       {
           gCounter += 1;
           if (gCounter > 1000000) {
               gCounter = 0;
           }
           gData.publish(gCounter);
       }
        // return false; //如果是这些事件产生的话，就返回真，即屏蔽掉这些事件，也就是安装有同类型的其他钩子，捕获不到同样的事件
    }
    return CallNextHookEx(mouseHook,nCode,wParam,lParam); //否则，如果返回给下一个钩子子程处理
}

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent),
    settings("settings.ini", QSettings::IniFormat),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);


    HINSTANCE hInstance = (HINSTANCE)::GetModuleHandle(NULL);
    mouseHook = SetWindowsHookEx(WH_MOUSE_LL, mouseProc, hInstance, NULL);//注册鼠标钩子
    // GetCurrentThreadId() 最后一个参数输入这个，就只能捕获到程序内部的事件
//    connect(timer, SIGNAL(timeout()), this, SLOT(heartBeatCheck()));

    // Qt::CustomizeWindowHint | Qt::WindowCloseButtonHint |
    setWindowFlags(Qt::Dialog| Qt::WindowStaysOnTopHint | Qt::FramelessWindowHint);

    rxqt::run_loop rxqt_run_loop;
    QTimer *timer = new QTimer();
    timer->start(1000);
    setWindowOpacity(0.8);

//    setAttribute(Qt::WA_TranslucentBackground, true);

//    this->setWindowFlags(Qt::FramelessWindowHint);
//    this->setWindowOpacity(1);
//    this->setAttribute(Qt::WA_TranslucentBackground);
//    setWindowOpacity(0.75);
//    QPalette palette;
//    palette.setColor(QPalette::Background, QColor(255, 255, 0));
//    this->ui->main_label->setAutoFillBackground(true);  //一定要这句，否则不行
//    this->ui->main_label->setPalette(palette);

    // 设置托盘图标
    QIcon *icon = new QIcon(":/icon/res/tea.png");
    setWindowIcon(*icon);
    pSysTrayIcon = new QSystemTrayIcon(this);
    pSysTrayIcon->setIcon(*icon);
    pSysTrayIcon->setToolTip(QObject::trUtf8("Reminder"));
    connect(pSysTrayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), this, SLOT(activeTray(QSystemTrayIcon::ActivationReason)));
    pSysTrayIcon->show();
    QDateTime current_date_time =QDateTime::currentDateTime();
    QString current_date =current_date_time.toString("yyyy.MM.dd hh:mm:ss.zzz ddd");
    // 设置托盘菜单
    pMenu = new QMenu(this);
    auto pActions1 = new QAction(pMenu);
    auto pActions2 = new QAction(pMenu);
    auto pActions3 = new QAction(pMenu);
    pActions1->setText("显示");
    pActions1->setIcon(QIcon(":/icon/res/windows.png"));
    pActions2->setText("设置");
    pActions2->setIcon(QIcon(":/icon/res/settings.png"));
    pActions3->setText("退出");
    pActions3->setIcon(QIcon(":/icon/res/exit.png"));
    pMenu->addAction(pActions1);
    pMenu->addAction(pActions2);
    pMenu->addAction(pActions3);
    connect(pActions1, &QAction::triggered, this, &MainWindow::showWindow);
    connect(pActions2, &QAction::triggered, this, &MainWindow::showSetting);
    connect(pActions3, &QAction::triggered, this, &MainWindow::OnExit);
    pSysTrayIcon->setContextMenu(pMenu);
    //settings.setValue("start_with", 1790);

    auto rx_timer = rxqt::from_signal(timer, &QTimer::timeout);

    // 这是一个控制变量，当按钮发出值时，被置于大于0，当时间到时被置于0，自动休息完毕的计时器当signal大于0时被屏蔽
    auto rx_autoContiue = gRestData.observable()
            .map([=](auto v) {
                if (v == 1) { return
                    rxqt::from_signal(timer, &QTimer::timeout)
                        .map([](auto){ return 1; })
                        .scan(0 ,[](int now, int pre){ return now + pre; })
                        .as_dynamic();
                } else { return
                     rxqt::from_signal(timer, &QTimer::timeout)
                            .map([](auto){ return 0; })
                            .take(1).filter([](auto v){ return v > 1; }).as_dynamic();
                }
            })
            .switch_on_next()
            .tap([=](int v) {
                if (v > 0) {
                    if (settings.value("auto_continue", 0).toInt() > 0)
                        ui->pbContinue->setText(QString("休息结束（%1/%2）").arg(v + 1).arg(settings.value("auto_continue", 0).toInt()));
                    else
                        ui->pbContinue->setText(QString("休息结束"));
                }
            })
            .filter([=](int v){
                return settings.value("auto_continue", 0).toInt() > 0 && v >= settings.value("auto_continue", 0).toInt();
            });  // 只有当大于零时才会发出值，实现了开关

    auto rx_mouse = gData.observable()
            .start_with(0)
            .map([](auto){return -100000;})  // 每次发出很大的负数用于清空结果
            .merge(rxqt::from_signal(timer, &QTimer::timeout).map([](auto){return 1;}) ) // 合并计时器
            .scan(settings.value("start_with", 0).toInt(), [](int now, int pre) { return now + pre > 0 ? now + pre : 0;});

    auto rx1 = rxqt::from_signal(this->ui->pbContinue, &QPushButton::clicked)
            .map([](auto){return 1;})
            .merge(rx_autoContiue)
            .tap([=](int){
                ui->pbContinue->setText(QString("休息结束"));
                gRestData.publish(0);
            })
            .start_with(0)
            .tap([=](auto){ this->hide(); })
            .map([=](auto) { return
                rxqt::from_signal(timer, &QTimer::timeout)   // 时间事件
                            .map([](auto){ return 1; })      // 必须转化为整数才能合并
                            .with_latest_from(rx_mouse)      // 这里combine了鼠标事件，鼠标事件中有计时器（且鼠标移动计时器会重置）
                            .map([=](auto v){return (std::get<1>(v) > 10 * 60 && settings.value("auto_pause", false).toBool()) ? 0 : 1 ;}) // 如果计时器很大说明鼠标好久没动了，于是判断人不在，返回0 否则1
                            .scan(settings.value("start_with", 0).toInt(), [](int now, int pre) { return now + pre;} )  // 累加
                            .pairwise()       // 本次与上一次
                            .as_dynamic();
    });

//    auto rxAutoRest =
    auto rx_merge = rx1.switch_on_next();  // 这个根据官网的例子写的
    // 鼠标点击计时按钮（默认开始自动点一次）然后开始循环
    rx_merge.subscribe([=](std::tuple<int, int> value){
        auto pre = std::get<0>(value);
        auto v = std::get<1>(value);
        auto all = settings.value("interval/0", 30).toInt() * 60;
        QTime time = QTime::currentTime();
        bool yushu = time.minute() % settings.value("interval/1", 1).toInt() == 0;
        bool isBack = pre > v;

        if (v > all && yushu && !isBack) {
            if (!this->ui->main_label->text().startsWith(QString("您已经"))) {
                this->ui->main_label->setText(QString("您已经工作%1分钟了，起来喝杯水吧！").arg(int(v/60 + 0.5f)));
                auto soundIndex = settings.value("play_sound", 0).toInt();
                if (soundIndex > 0) {
                    QSound::play(QString(":/sound/res/rest%1.wav").arg(soundIndex));
                }
                gRestData.publish(1);
            }
        } else {
            this->ui->main_label->setText(QString("当前工作时间：%1/%2").arg(v).arg(all));
        }
    });
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::heartBeatCheck()
{
    this->second += 1;

}

void MainWindow::changLabel()
{
    this->second += 1;
    QDateTime current_date_time =QDateTime::currentDateTime();
    QString current_date =current_date_time.toString("yyyy.MM.dd hh:mm:ss.zzz ddd");
    this->ui->main_label->setText(current_date);
}


void MainWindow::showWindow()
{
    if (this->isHidden()) {
        this->show();
    } else {
        this->hide();
    }
}

void MainWindow::showSetting()
{
    if(!this->pSetting) {
        this->pSetting = new Setting();
    }
    this->pSetting->show();
}

void MainWindow::showMenu()
{
    if(this->isHidden()) {
        pMenu->actions()[0]->setText("显示");
    } else {
        pMenu->actions()[0]->setText("隐藏");
    }
    pMenu->show();
}

void MainWindow::OnExit()
{
    QApplication::exit(0);
}

void MainWindow::closeEvent(QCloseEvent *event)
{
    this->hide();
    event->ignore();
}

void MainWindow::activeTray(QSystemTrayIcon::ActivationReason reason)
{
    switch (reason)
    {
    case QSystemTrayIcon::Context:
        showMenu();
        break;
    case QSystemTrayIcon::DoubleClick:
        showSetting();
        break;
    case QSystemTrayIcon::Trigger:
        break;
    }
}

